package com.yuw.reflection.classdemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;

public class TestDriver {

	public static void main(String[] args) {
		test05();
	}

	/**
	 * 使用反射获取一个类中的所有构造方法 构造方法方法的反射调用
	 */
	private static void test05() {
		// 获取一个类的Class实例
		// 获取该类的Class实例对象
		Student stu0 = new Student();
		// 设置姓名属性的值
		stu0.setStuName("小明");

		Class<? extends Student> clazzStu = stu0.getClass();

		// 创建一个新的Student对象实例
		Student stu1 = new Student();
		stu1.setStuName("小李");

		// 获取所有的构造方法信息
		Constructor<?>[] constructors = clazzStu.getDeclaredConstructors();
		// 输出每个构造方法的信息
		for (Constructor<?> constructor : constructors) {
			System.out.print(Modifier.toString(constructor.getModifiers()) + "  ");
			System.out.print(constructor.getName() + "  ");
			for (Class clazzType : constructor.getParameterTypes()) {
				// 输出参数类型
				System.out.print(clazzType.getName() + ",  ");
			}

			// 换行
			System.out.println();
		}
		System.out.println("======使用反射操作构造方法=======");
		try {
			// 获取指定参数列表的构造方法
			// 变长参数指定形参列表
			Constructor<? extends Student> constructorStu = clazzStu.getDeclaredConstructor(String.class, String.class,
					String.class, String.class, String.class);
			// 反射调用构造方法获取该类的一个新的实例对象
			// 给定构造方法的实参列表，形参和实参一一对应
			//Student stu01 = constructorStu.newInstance("小明", "15001", "河北工大", "男", "30");
			Student stu01 = constructorStu.newInstance(new String[]{"小明", "15001", "河北工大", "男", "30"});
			System.out.println("stu01:" + stu01.toString());
			System.out.println("stu0==stu01:" + (stu0 == stu01));
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * 使用反射获取一个类中的所有行为方法 方法的反射调用
	 */
	private static void test04() {
		// 获取一个类的Class实例
		// 获取该类的Class实例对象
		Student stu0 = new Student();
		// 设置姓名属性的值
		stu0.setStuName("小明");

		Class<? extends Student> clazzStu = stu0.getClass();

		// 创建一个新的Student对象实例
		Student stu1 = new Student();
		stu1.setStuName("小李");

		// 获取所有的方法信息
		Method[] methods = clazzStu.getDeclaredMethods();
		// 打印方法的信息
		for (Method method : methods) {
			// 使用反射获取访问控制修饰符
			System.out.print(Modifier.toString(method.getModifiers()) + "  ");
			// 返回类型
			System.out.print(method.getGenericReturnType().getTypeName() + "  ");
			// 方法名
			System.out.print(method.getName() + "  ");
			// 获取形参列表数组
			Type[] parasTypes = method.getGenericParameterTypes();
			System.out.print("(");
			for (Type type : parasTypes) {
				System.out.print(type.getTypeName() + ",  ");
			}
			System.out.println(" ) ");
		}

		System.out.println("======使用反射操作方法=======");
		try {
			// 通过方法名和方法的形参列表获取指定类型的方法对象【方法重载，所以不能通过方法名获取】
			Method mDoStuding = clazzStu.getDeclaredMethod("doStuding", String.class);
			// 使用Method对象的invoke方法，来执行该方法
			// invoke的第一个参数是被绑定的类的实例对象，第二个变长参数是执行该方法是所需要的实参列表
			// 注意：invoke的第二个参数的实参列表需要和获取该方法对象时给的形参列表保持一一对应；
			mDoStuding.invoke(stu0, "school");

			System.out.println("======================");
			stu0.doStuding("school");

		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 使用反射获取一个类中的所有属性信息
	 */
	private static void test03() {
		// 获取该类的Class实例对象
		Student stu0 = new Student();
		// 设置姓名属性的值
		stu0.setStuName("小明");

		Class<? extends Student> clazzStu2 = stu0.getClass();

		// 创建一个新的Student对象实例
		Student stu1 = new Student();
		stu1.setStuName("小李");

		// 获取所有的属性信息
		Field[] fields = clazzStu2.getDeclaredFields();
		// 循环数组，遍历每个属性的内容
		for (Field field : fields) {
			System.out.print(Modifier.toString(field.getModifiers()) + "  ");
			System.out.print(field.getGenericType().getTypeName() + "  ");
			System.out.println(field.getName());
		}

		System.out.println("============================");
		try {
			// 获取指定名字的属性对象
			Field fieldStuName = clazzStu2.getDeclaredField("stuName");
			// 设置可以方法私有属性的权限:true表示可以操作私有的对象
			fieldStuName.setAccessible(true);
			// 获取该属性在某个指定的对象实例上的值
			Object objName = fieldStuName.get(stu0);
			System.out.println("获取的stu0的实例对象的姓名属性的值为：" + objName);

			System.out.println("获取的stu0的实例对象的姓名属性的值为：" + fieldStuName.get(stu1));

			System.out.println("=====使用反射机制操作一个类的属性======");
			System.out.println("stu0:" + stu0.toString());
			// 通过反射的属性对象，外部改变某一个实例对象的当前属性的值
			// 第一个参数是被操作类的实例对象stu0，第二个参数被操作属性的值
			fieldStuName.set(stu0, "小赵");

			System.out.println("stu0:" + stu0.toString());

		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 获取一个类Class类实例对象创建被描述类的实例对象
	 */
	private static void test02() {
		// 获取Student类的Class实例对象
		Class<Student> clazzStu1 = Student.class;
		// 通过newInstance方法获取Class描述的类的实例对象
		try {
			Student stu0 = clazzStu1.newInstance();
			// 调用方法设值属性
			stu0.setStuName("小明");
			System.out.println("反射获取的Student类实例对象：" + stu0.toString());
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 获取一个类或某个实例对象的Class类实例对象
	 */
	private static void test01() {
		// （1）通过class静态属性，例如：类名.class获取
		Class<Student> clazzStu1 = Student.class;
		// （2）通过被描述类的实例对象的getClass方法获取
		Student stu0 = new Student();
		Class clazzStu2 = stu0.getClass();
		// （3）使用Class类提供的静态方法forName获取
		try {
			// 参数为包路径名
			Class clazzStu3 = Class.forName("com.yuw.reflection.classdemo.Student");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
